#include "sal.h"
#include "ctc_cli.h"
#include "usw/include/drv_enum.h"
#include "drv_api.h"
#include "usw/include/drv_common.h"
#include "usw/include/drv_chip_ctrl.h"
#include "ctc_dkit.h"
#include "ctc_dkit_common.h"
#include "ctc_usw_dkit_misc.h"
#include "ctc_usw_dkit.h"
#include "ctc_usw_dkit_dump_cfg.h"

#define DKIT_SERDES_ID_MAX 83

#define DKITS_SERDES_ID_CHECK(ID) \
    do { \
        if(ID >= DKIT_SERDES_ID_MAX) \
        {\
            CTC_DKIT_PRINT("serdes id %d exceed max id %d!!!\n", ID, DKIT_SERDES_ID_MAX-1);\
            return DKIT_E_INVALID_PARAM; \
        }\
    } while (0)
    
struct ctc_dkit_tmg_serdes_ctl_loopback_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 mode;
};


typedef struct ctc_dkit_tmg_serdes_ctl_loopback_s ctc_dkit_tmg_serdes_ctl_loopback_t;

struct ctc_dkit_tmg_serdes_ctl_eye_s
{
    uint16 serdes_id;
    uint8 eye_type;
    uint32 read_times;
};
typedef struct ctc_dkit_tmg_serdes_ctl_eye_s ctc_dkit_tmg_serdes_ctl_eye_t;

struct ctc_dkit_tmg_serdes_ctl_ffe_s
{
    uint16 serdes_id;
    uint16 dest_serdes_id;
    uint8 prbs_pattern;
    uint32 threshold;//coefficient sum threshold
    uint32 delay;
    char *str;
    ctc_dkit_serdes_para_ffe_t *ffe;
};
typedef struct ctc_dkit_tmg_serdes_ctl_ffe_s ctc_dkit_tmg_serdes_ctl_ffe_t;

struct ctc_dkit_tmg_serdes_ctl_pol_check_s
{
    uint16 serdes_id;
    uint8 paired_serdes_id;
};
typedef struct ctc_dkit_tmg_serdes_ctl_pol_check_s ctc_dkit_tmg_serdes_ctl_pol_check_t;


struct ctc_dkit_tmg_serdes_ctl_dfe_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 delta;
    int8 taps[5];
    int32 taps_pam4[5];
};
typedef struct ctc_dkit_tmg_serdes_ctl_dfe_s ctc_dkit_tmg_serdes_ctl_dfe_t;

struct ctc_dkit_tmg_serdes_ctl_fw_s
{
    uint16 serdes_id;
    uint8 oper;
};
typedef struct ctc_dkit_tmg_serdes_ctl_fw_s ctc_dkit_tmg_serdes_ctl_fw_t;

struct ctc_dkit_tmg_serdes_ctl_bathtub_s
{
    uint16 serdes_id;
    uint8 oper;
    uint8 depth;
};
typedef struct ctc_dkit_tmg_serdes_ctl_bathtub_s ctc_dkit_tmg_serdes_ctl_bathtub_t;



struct ctc_dkit_at_serdes_ber_array_s
{
    uint8 size;
    uint8 ber_array[DKIT_SERDES_ID_MAX];
};
typedef struct ctc_dkit_at_serdes_ber_array_s ctc_dkit_at_serdes_ber_array_t;

struct ctc_dkit_at_serdes_ber_mon_s
{
    uint8 lchip;
    ctc_dkit_at_serdes_ber_array_t ber_array;
    uint32 dkit_at_prbs_err_cnt_mon[DKIT_SERDES_ID_MAX];
    uint32 dkit_at_prbs_err_cnt_carry[DKIT_SERDES_ID_MAX];
    sal_time_t dkit_at_prbs_rst_tv[DKIT_SERDES_ID_MAX];
};
typedef struct ctc_dkit_at_serdes_ber_mon_s ctc_dkit_at_serdes_ber_mon_t;

struct ctc_dkit_tmg_serdes_ctl_prbs_s
{
    uint8 lchip;
    uint16 serdes_id;
    uint8 oper;
    uint8 prbs_pattern;
    uint8 is_keep;
    uint32 delay_before_check;
    uint32 error_count;
    uint32 nano_ber;
    char *str;
};
typedef struct ctc_dkit_tmg_serdes_ctl_prbs_s ctc_dkit_tmg_serdes_ctl_prbs_t;




int32
ctc_tmg_dkit_misc_read_serdes(void* para)
{
    uint32 addr = 0;
    uint8 hss_id = 0;
    ctc_dkit_serdes_wr_t* p_para = (ctc_dkit_serdes_wr_t*)para;

    DKITS_PTR_VALID_CHECK(p_para);
    DKITS_SERDES_ID_CHECK(p_para->serdes_id);
    CTC_DKIT_LCHIP_CHECK(p_para->lchip);

    //(void)_ctc_tmm_dkit_internal_convert_serdes_addr(p_para, &addr, &hss_id);
    //(void)drv_chip_read_hss28g(p_para->lchip, hss_id, addr, &p_para->data);
    CTC_DKIT_PRINT_DEBUG("read  chip id:%d, hss id:%d, addr: 0x%04x, value: 0x%04x\n", p_para->lchip, hss_id, addr, p_para->data);
    
    return CLI_SUCCESS;
}

int32
ctc_tmg_dkit_misc_write_serdes(void* para)
{
    uint32 addr = 0;
    uint8 hss_id = 0;
    //uint16 data = 0;
    ctc_dkit_serdes_wr_t* p_para = (ctc_dkit_serdes_wr_t*)para;

    DKITS_PTR_VALID_CHECK(p_para);
    DKITS_SERDES_ID_CHECK(p_para->serdes_id);
    CTC_DKIT_LCHIP_CHECK(p_para->lchip);

    CTC_DKIT_PRINT_DEBUG("write chip id:%d, hss id:%d, addr: 0x%04x, value: 0x%04x\n", p_para->lchip, hss_id, addr, p_para->data);

    return CLI_SUCCESS;
}

void *
_ctc_tmg_dkit_misc_serdes_ctl_param_convert(ctc_dkit_serdes_ctl_para_t *p_para)
{
    ctc_dkit_tmg_serdes_ctl_loopback_t  *loopback_param = NULL;
    ctc_dkit_tmg_serdes_ctl_prbs_t      *prbs_param = NULL;
    ctc_dkit_tmg_serdes_ctl_eye_t       *eye_param = NULL;
    ctc_dkit_tmg_serdes_ctl_ffe_t       *ffe_param = NULL;
    ctc_dkit_tmg_serdes_ctl_pol_check_t  *pol_check_param = NULL;
    ctc_dkit_tmg_serdes_ctl_dfe_t       *dfe_param = NULL;
    ctc_dkit_tmg_serdes_ctl_fw_t        *fw_param = NULL;
    ctc_dkit_tmg_serdes_ctl_bathtub_t   *bathtub_param = NULL;
    
    void *p_data = NULL;

    switch (p_para->type)
    {
        case CTC_DKIT_SERDIS_CTL_LOOPBACK:
            loopback_param = (ctc_dkit_tmg_serdes_ctl_loopback_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_loopback_t));
            if (NULL == loopback_param)
            {
                break;
            }
            loopback_param->serdes_id = p_para->serdes_id;
            loopback_param->oper = p_para->para[0];
            loopback_param->mode = p_para->para[1];
            p_data = loopback_param;
            break;
        case CTC_DKIT_SERDIS_CTL_PRBS:
            prbs_param = (ctc_dkit_tmg_serdes_ctl_prbs_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_prbs_t));
            if (NULL == prbs_param)
            {
                break;
            }
            prbs_param->lchip = p_para->lchip;
            prbs_param->serdes_id = p_para->serdes_id;
            prbs_param->oper = p_para->para[0];
            prbs_param->prbs_pattern = p_para->para[1];
            prbs_param->is_keep = p_para->para[2];
            prbs_param->delay_before_check = p_para->para[3];
            prbs_param->error_count = p_para->para[4];
            prbs_param->str = p_para->str;
            p_data = prbs_param;
            break;
        case CTC_DKIT_SERDIS_CTL_EYE:
            eye_param = (ctc_dkit_tmg_serdes_ctl_eye_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_eye_t));
            if (NULL == eye_param)
            {
                break;
            }
            eye_param->serdes_id = p_para->serdes_id;
            eye_param->eye_type = p_para->para[0];
            eye_param->read_times = p_para->para[1];
            p_data = eye_param;
            break;
        case CTC_DKIT_SERDIS_CTL_FFE:
            ffe_param = (ctc_dkit_tmg_serdes_ctl_ffe_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_ffe_t));
            if (NULL == ffe_param)
            {
                break;
            }
            ffe_param->serdes_id = p_para->serdes_id;
            ffe_param->dest_serdes_id = p_para->para[0];
            ffe_param->prbs_pattern = p_para->para[1];
            ffe_param->threshold = p_para->para[2];
            ffe_param->delay = p_para->para[3];
            ffe_param->str = p_para->str;
            ffe_param->ffe = &p_para->ffe;
            p_data = ffe_param;
            break;
        case CTC_DKIT_SERDIS_CTL_STATUS:
        case CTC_DKIT_SERDIS_CTL_ISI:
        case CTC_DKIT_SERDIS_CTL_DELAT_PH:
            break;
        case CTC_DKIT_SERDIS_CTL_POLR_CHECK:
            pol_check_param = (ctc_dkit_tmg_serdes_ctl_pol_check_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_pol_check_t));
            if (NULL == pol_check_param)
            {
                break;
            }
            pol_check_param->serdes_id = p_para->serdes_id;
            pol_check_param->paired_serdes_id = p_para->para[0];
            p_data = eye_param;
            break;
        case CTC_DKIT_SERDIS_CTL_DFE:
        case CTC_DKIT_SERDIS_CTL_GET_DFE:
            dfe_param = (ctc_dkit_tmg_serdes_ctl_dfe_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_dfe_t));
            if (NULL == dfe_param)
            {
                break;
            }
            dfe_param->serdes_id = p_para->serdes_id;
            dfe_param->oper = p_para->para[0];
            dfe_param->taps[0] = (uint8)(p_para->para[1] & 0xff);
            dfe_param->taps[1] = (uint8)(p_para->para[1] & (0xff << 8));
            dfe_param->taps[2] = (uint8)(p_para->para[1] & (0xff << 16));
            dfe_param->taps[3] = (uint8)(p_para->para[1] & (0xff << 24));
            dfe_param->taps[4] = (uint8)(p_para->para[2] & 0xff);
            p_data = dfe_param;
            break;
        case CTC_DKIT_SERDIS_CTL_FW:
            fw_param = (ctc_dkit_tmg_serdes_ctl_fw_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_fw_t));
            if (NULL == fw_param)
            {
                break;
            }
            fw_param->serdes_id = p_para->serdes_id;
            fw_param->oper = p_para->para[0];
            p_data = fw_param;
            break;
        case CTC_DKIT_SERDIS_CTL_BATHTUB:
            bathtub_param = (ctc_dkit_tmg_serdes_ctl_bathtub_t*)mem_malloc(MEM_CLI_MODULE, sizeof(ctc_dkit_tmg_serdes_ctl_bathtub_t));
            if (NULL == bathtub_param)
            {
                break;
            }
            bathtub_param->serdes_id = p_para->serdes_id;
            bathtub_param->oper = p_para->para[0];
            bathtub_param->depth = p_para->para[1];
            p_data = bathtub_param;
            break;
        default:
            break;
    }
    
    return p_data;
}


int32
ctc_tmg_dkit_misc_serdes_ctl(void* p_para)
{
    uint8 lchip;
    ctc_dkit_serdes_ctl_para_t* p_serdes_para = (ctc_dkit_serdes_ctl_para_t*)p_para;
    void *p_param = NULL;

    DKITS_PTR_VALID_CHECK(p_serdes_para);
    lchip = p_serdes_para->lchip;
    CTC_DKIT_LCHIP_CHECK(lchip);
    DRV_INIT_CHECK(lchip);

    p_param = _ctc_tmg_dkit_misc_serdes_ctl_param_convert(p_serdes_para);

    if((CTC_DKIT_SERDIS_CTL_STATUS != p_serdes_para->type) && (CTC_DKIT_SERDIS_CTL_ISI != p_serdes_para->type) &&  \
        (CTC_DKIT_SERDIS_CTL_DELAT_PH != p_serdes_para->type))
    {
        DKITS_PTR_VALID_CHECK(p_param);
    }
    
    switch (p_serdes_para->type)
    {
        case CTC_DKIT_SERDIS_CTL_LOOPBACK:
            break;
        case CTC_DKIT_SERDIS_CTL_PRBS:
            break;
        case CTC_DKIT_SERDIS_CTL_EYE:
            break;
        case CTC_DKIT_SERDIS_CTL_FFE:
            break;
        case CTC_DKIT_SERDIS_CTL_STATUS:
            break;
        case CTC_DKIT_SERDIS_CTL_POLR_CHECK:
            break;
        case CTC_DKIT_SERDIS_CTL_DFE:
            break;
        case CTC_DKIT_SERDIS_CTL_GET_DFE:
            break;
        case CTC_DKIT_SERDIS_CTL_FW:
            break;
        case CTC_DKIT_SERDIS_CTL_ISI:
            break;
        case CTC_DKIT_SERDIS_CTL_DELAT_PH:
            break;
        case CTC_DKIT_SERDIS_CTL_BATHTUB:
            break;
        default:
            break;
    }

    mem_free(p_param);

    return CLI_SUCCESS;
}

int32
ctc_tmg_dkit_misc_serdes_diag(uint8 lchip, void* para)
{
#if 0
    uint32 diag_id = 0;
    uint8  serdes_id = 0;
    ctc_dkit_serdes_diag_para_t* p_para = (ctc_dkit_serdes_diag_para_t*)para;
 
    if((p_para->param_cnt > 63) || (p_para->param_cnt == 0) || (p_para->p_param == NULL))
    {
        CTC_DKIT_PRINT("Invalid param number!\n");
        return CLI_SUCCESS;
    }
    serdes_id = (uint8)(p_para->serdes_id);
    if(serdes_id > 99)
    {
        CTC_DKIT_PRINT("Invalid serdes id %u!\n", serdes_id);
        return CLI_SUCCESS;
    }
    diag_id = p_para->p_param[0];
    switch(diag_id)
    {
        case 0:
            if(7 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("ffe_taps: Input param number illegal, gaving %u expecting 6.\n", p_para->param_cnt-1);
                return CLI_SUCCESS;
            }
            (void)_ctc_tmm_dkit_misc_serdes_ffe_taps(lchip, serdes_id, (uint16)p_para->p_param[1], (uint16)p_para->p_param[2], 
                (uint16)p_para->p_param[3], (uint16)p_para->p_param[4], (uint16)p_para->p_param[5], (uint16)p_para->p_param[6]);
            break;
        case 1:
            if(5 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("ffe_pol: Input param number illegal, gaving %u expecting 4.\n", p_para->param_cnt-1);
                return CLI_SUCCESS;
            }
            (void)_ctc_tmm_dkit_misc_serdes_ffe_pol(lchip, serdes_id, (uint16)p_para->p_param[1], (uint16)p_para->p_param[2], 
                (uint16)p_para->p_param[3], (uint16)p_para->p_param[4]);
            break;
        case 2:
            if(2 != p_para->param_cnt)
            {
                CTC_DKIT_PRINT("abnormal intr check : Input param number illegal, gaving %u expecting 1.\n", p_para->param_cnt-1);
            }
            (void)_ctc_tmg_dkit_check_abnormal_intr(lchip, (uint8)p_para->p_param[1]);
        default:
            break;
    }
#endif    
    return CLI_SUCCESS;
}

int32
ctc_tmg_dkit_misc_serdes_reset(uint8 lchip, uint16 serdes_id)
{
    return CLI_SUCCESS;
}
